`timescale 1ns / 1ns

module tm_spimaster(       
		input    clk_i       ,
		input    rst_i       ,
		output   spi_ssel_o  ,
		output   spi_sck_o   ,
		output   spi_mosi_o  ,
		input    spi_miso_i  
		);	


wire       di_req;
reg  [7:0] di=0;
reg        wren=0;
wire       wr_ack;
wire       do_valid;
wire [7:0] data;




spi_master #(   
        .N (8)
        )
        u_spi_master (  
        .sclk_i        (clk_i      ),
        .pclk_i        (clk_i      ),
        .rst_i         (!rst_i    ),
        .spi_ssel_o    (spi_ssel_o),
        .spi_sck_o     (spi_sck_o ),
        .spi_mosi_o    (spi_mosi_o),
        .spi_miso_i    (spi_miso_i),
        .di_req_o      (di_req    ),
        .di_i          (di        ),
        .wren_i        (wren      ),
        .wr_ack_o      (wr_ack    ),
        .do_valid_o    (do_valid  ),
        .do_o          (data      ),
        .sck_ena_o     (          ),
        .sck_ena_ce_o  (          ),
        .do_transfer_o (          ),
        .wren_o        (          ),
        .rx_bit_reg_o  (          ),
        .state_dbg_o   (          ),
        .core_clk_o    (          ),
        .core_n_clk_o  (          ),
        .core_ce_o     (          ),
        .core_n_ce_o   (          ),
        .sh_reg_dbg_o  (          )
    );                      


task send_byte;
	input is_first;
	input [7:0]data;
begin
  if (is_first==1'b0)
  begin
 		 @(posedge clk_i)	;
	  	while(di_req==1'b0)  	@(posedge clk_i)	;
	end

	@(posedge clk_i);
		wren=1'b1;
		di=data;

	@(posedge clk_i);
	while  (wr_ack==1'b0) 	@(posedge clk_i)	;
	
	@(posedge clk_i);
	wren=1'b0;
	
 	@(posedge clk_i);
	while  (wr_ack==1'b1) 	@(posedge clk_i)	;
	
//	$display("data is %b",data);
end
endtask	


task send_finish;
begin
 		 @(posedge clk_i)	;
	  	while(spi_ssel_o==1'b0)  	@(posedge clk_i)	;
end
endtask



task rec_byte;
	output [7:0]rdata;
begin
	@(posedge clk_i);
	while  (do_valid==1'b0) 	@(posedge clk_i)	;
	rdata = data;
	
 	@(posedge clk_i);
	while  (do_valid==1'b1) 	@(posedge clk_i)	;
end
endtask	

task spi_op;
	input [7:0] cmd;
	input [31:0] addr;
	input [7:0] size;
	input [7:0] bytemsk;
	input [31:0] wdata;
	//output [31:0] rdata_mem[15:0];
	output[31:0] rdat;
  reg [31:0] rdata;
  integer i;
  
begin
  
		send_byte(1,cmd);
		send_byte(0,addr[31:24]);
		send_byte(0,addr[23:16]);
		send_byte(0,addr[15:8]);
		send_byte(0,addr[7:0]);
		send_byte(0,size);
		send_byte(0,bytemsk);
		if (cmd==8'b00000000)
		begin
			send_byte(0,wdata[31:24]);
			send_byte(0,wdata[23:16]);
			send_byte(0,wdata[15:8]);
			send_byte(0,wdata[7:0]);
			send_finish;
			$display("spi wr :addr = %h  , wdata = %h",addr,wdata);
		end
		else if (cmd==8'b00000001)
			fork
				begin
					repeat (size+1)
					begin
						send_byte(0,8'b00000000);
						send_byte(0,8'b00000000);
						send_byte(0,8'b00000000);
						send_byte(0,8'b00000000);
					end
				  send_finish;
				end
				
				begin
					rec_byte(rdata[7:0]); //droped
					for (i=0;i<=size;i=i+1)
					begin
						rec_byte(rdata[31:24]);
						rec_byte(rdata[23:16]);
						rec_byte(rdata[15:8]);
						rec_byte(rdata[7:0]);
						//rdata_mem[i]=rdata;
						rdat = rdata;
						$display("spi rd :addr = %h , rdata = %h",addr+i,rdata);
					end
				end
			join
				
end	
endtask


task sp6_op;
	input [7:0] cmd1;
	input [7:0] cs;
	input [7:0] cmd2;
	input [23:0] addr;
	input [15:0] wdata;
	output[15:0] rdat;
  	reg [15:0] rdata;
  integer i;
  
begin
  
		send_byte(1,cmd1);
		send_byte(1,cs);
		send_byte(1,cmd2);
		send_byte(0,addr[23:16]);
		send_byte(0,addr[15:8]);
		send_byte(0,addr[7:0]);
		if (cmd2==8'h02)
		begin
			send_byte(0,wdata[15:8]);
			send_byte(0,wdata[7:0]);
			send_finish;
			$display("spi wr :addr = %h  , wdata = %h",addr,wdata);
		end
		else if (cmd2==8'h03)
			fork
				begin
					repeat (0+1)
					begin
						send_byte(0,8'b00000000);
						send_byte(0,8'b00000000);
					end
				  send_finish;
				end
				
				begin
					rec_byte(rdata[7:0]); //droped
					for (i=0;i<=0;i=i+1)
					begin
						rec_byte(rdata[15:8]);
						rec_byte(rdata[7:0]);
						//rdata_mem[i]=rdata;
						rdat = rdata;
						$display("spi rd :addr = %h , rdata = %h",addr+i,rdata);
					end
				end
			join
				
end	
endtask

task wsp6;
	input [23:0] 	addri;
	input [15:0]	dati;
	reg [15:0] rdat;
begin
	sp6_op(8'h00,8'h01,8'd2,addri,dati,rdat);
end
endtask

task rsp6;
	input [23:0]	addri;
	output[15:0]	dato;
	
begin
	sp6_op(8'h00,8'h01,8'd3,addri,16'd0,dato);
end
endtask




task sp3_op;
	input [7:0] cmd1;
	input [7:0] cs;
	input [7:0] cmd2;
	input [15:0] addr;
	input [7:0] wdata;
	output[7:0] rdat;
  	reg [7:0] rdata;
  integer i;
  
begin
  
		send_byte(1,cmd1);
		send_byte(1,cs);
		send_byte(1,cmd2);
		send_byte(0,addr[15:8]);
		send_byte(0,addr[7:0]);
		if (cmd2==8'h02)
		begin
			send_byte(0,wdata[7:0]);
			send_finish;
			$display("spi wr :addr = %h  , wdata = %h",addr,wdata);
		end
		else if (cmd2==8'h03)
			fork
				begin
					repeat (0+1)
					begin
						send_byte(0,8'b00000000);
					end
				  send_finish;
				end
				
				begin
					rec_byte(rdata[7:0]); //droped
					for (i=0;i<=0;i=i+1)
					begin
						rec_byte(rdata[7:0]);
						//rdata_mem[i]=rdata;
						rdat = rdata;
						$display("spi rd :addr = %h , rdata = %h",addr+i,rdata);
					end
				end
			join
				
end	
endtask

task wsp3;
	input [15:0] 	addri;
	input [7:0]	dati;
	reg [7:0] rdat;
begin
	sp3_op(8'h00,8'h02,8'd2,addri,dati,rdat);
end
endtask

task rsp3;
	input [15:0]	addri;
	output[7:0]	dato;
	
begin
	sp3_op(8'h00,8'h02,8'd3,addri,8'd0,dato);
end
endtask




endmodule